/* Orbas Naming Server:
 *     A open source CORBA CosNaming implementation from Huihoo.
 *
 * Copyright 2003 Huihoo Power, Inc. All Right Reserved.
 *
 * This software is licensed under LGPL license.
 * See terms of license at gnu.org.
 *
 * For more information, visit:
 *
 * http://www.huihoo.org/orbas
 */
package org.huihoo.orbas.naming;

/**
 * <p>Description: </p>
 * Namingcontext Implemention.
 * <p>Copyright (c) 2003</p>
 * <p>Company: <a href="http://www.huihoo.org/orbas">huihoo.org</a></p>
 * @author <a href="http://www.huihoo.org/~cocia">Cocia Lin(cocia@163.com)</a>
 * @see <a href="http://www.huihoo.org/orbas">http://www.huihoo.org/orbas</a>
 * @version 1.0
 */

import java.util.Enumeration;
import java.util.Hashtable;

import org.huihoo.orbas.naming.util.CorbaLoc;
import org.omg.CORBA.ORB;
import org.omg.CORBA.Object;
import org.omg.CosNaming.Binding;
import org.omg.CosNaming.BindingIteratorHelper;
import org.omg.CosNaming.BindingIteratorHolder;
import org.omg.CosNaming.BindingListHolder;
import org.omg.CosNaming.BindingType;
import org.omg.CosNaming.NameComponent;
import org.omg.CosNaming.NamingContext;
import org.omg.CosNaming.NamingContextExt;
import org.omg.CosNaming.NamingContextExtHelper;
import org.omg.CosNaming.NamingContextExtPOA;
import org.omg.CosNaming.NamingContextExtPackage.InvalidAddress;
import org.omg.CosNaming.NamingContextPackage.AlreadyBound;
import org.omg.CosNaming.NamingContextPackage.CannotProceed;
import org.omg.CosNaming.NamingContextPackage.InvalidName;
import org.omg.CosNaming.NamingContextPackage.NotEmpty;
import org.omg.CosNaming.NamingContextPackage.NotFound;
import org.omg.CosNaming.NamingContextPackage.NotFoundReason;
import org.omg.PortableServer.POA;

//import org.omg.CORBA_2_5.ORB;

public class NamingContextExtImpl extends NamingContextExtPOA {
	/**
	 * Private Section.
	 */
	//
	private Hashtable names = new Hashtable();
	private Hashtable contexts = new Hashtable();
	// orb and poa reference.
	ORB orb;
	POA poa;
	POA rootPoa;
	// record the children number of this.
	private int child_count = 0;

	/**
	 * roseuid 3E8D3C4401FB
	 */
	public NamingContextExtImpl(ORB orb, POA poa) {
		this.orb = orb;
		this.poa = poa;
		//
		try {
			// Get the RootPOA.
			this.rootPoa = org.omg.PortableServer.POAHelper.narrow(orb
					.resolve_initial_references("RootPOA"));
		} catch (org.omg.CORBA.ORBPackage.InvalidName in) {
			in.printStackTrace();
		}

	}

	/**
	 * @param n
	 * @return String
	 * @throws org.omg.CosNaming.NamingContextPackage.InvalidName
	 *             roseuid 3E8A61A1032C
	 */
	public String to_string(NameComponent[] n) throws InvalidName {
		// Valid the parameter.
		if (n == null || n.length == 0) {
			throw new InvalidName();
		}
		/*
		 * StringBuffer name = new StringBuffer(); String sepertor1 = "/";
		 * String sepertor2 = "."; for (int i = 0; i < n.length; i++) {
		 * NameComponent nc = n[i]; if (i > 0) { name.append(sepertor1); } //
		 * name.append(nc.id); if (nc.kind != null) { name.append(sepertor2); }
		 * }
		 */
		return Name.toString(n);
	}

	/**
	 * @param sn
	 * @return org.omg.CosNaming.NameComponent[]
	 * @throws org.omg.CosNaming.NamingContextPackage.InvalidName
	 *             roseuid 3E8A61A1034B
	 */
	public NameComponent[] to_name(String sn) throws InvalidName {
		if (sn == null || sn.length() == 0) {
			throw new InvalidName();
		}
		return Name.toName(sn);
	}

	/**
	 * @param addr
	 * @param sn
	 * @return String
	 * @throws org.omg.CosNaming.NamingContextExtPackage.InvalidAddress
	 * @throws org.omg.CosNaming.NamingContextPackage.InvalidName
	 *             roseuid 3E8A61A1036B
	 */
	public String to_url(String addr, String sn) throws InvalidAddress,
			InvalidName {
		CorbaLoc corbaLoc;
		try {
			corbaLoc = new CorbaLoc(addr);
			return corbaLoc.toCorbaName(sn);
		} catch (IllegalArgumentException ia) {
			throw new InvalidAddress();
		}

	}

	/**
	 * @param sn
	 * @return org.omg.CORBA.Object
	 * @throws org.omg.CosNaming.NamingContextPackage.NotFound
	 * @throws org.omg.CosNaming.NamingContextPackage.CannotProceed
	 * @throws org.omg.CosNaming.NamingContextPackage.InvalidName
	 *             roseuid 3E8A61A10399
	 */
	public Object resolve_str(String sn) throws NotFound, CannotProceed,
			InvalidName {
		NameComponent[] nc = to_name(sn);
		return resolve(nc);
	}

	/**
	 * @throws org.omg.CosNaming.NamingContextPackage.NotEmpty
	 *             roseuid 3E8A61A103B9
	 */
	public void destroy() throws NotEmpty {

	}

	/**
	 * @param nc
	 * @param obj
	 * @throws org.omg.CosNaming.NamingContextPackage.NotFound
	 * @throws org.omg.CosNaming.NamingContextPackage.CannotProceed
	 * @throws org.omg.CosNaming.NamingContextPackage.InvalidName
	 * @throws org.omg.CosNaming.NamingContextPackage.AlreadyBound
	 *             roseuid 3E8A61A103C8
	 */
	public void bind(NameComponent[] nc, Object obj) throws NotFound,
			CannotProceed, InvalidName, AlreadyBound {

		if (nc == null || nc.length == 0)
			throw new InvalidName();

		if (obj == null)
			throw new org.omg.CORBA.BAD_PARAM();

		Name n = new Name(nc);
		Name ctx = n.ctxName();
		NameComponent nb = n.baseNameComponent();
		if (ctx == null) {
			if (names.containsKey(n)) {
				// if the name is still in use, try to ping the object
				org.omg.CORBA.Object s = (org.omg.CORBA.Object) names.get(n);
				if (s._non_existent()) {
					rebind(n.components(), obj);
					return;
				}
				throw new AlreadyBound();
			} else if (contexts.containsKey(n)) {
				// if the name is still in use, try to ping the object
				org.omg.CORBA.Object s = (org.omg.CORBA.Object) contexts.get(n);
				if (s._non_existent()) {
					unbind(n.components());
				}
				throw new AlreadyBound();
			}

			if ((names.put(n, obj)) != null)
				throw new CannotProceed(_this(), n.components());
			System.out.println("Bound name: " + n.toString());

		} else {
			NameComponent[] ncx = new NameComponent[1];
			ncx[0] = nb;
			NamingContextExtHelper.narrow(resolve(ctx.components())).bind(ncx,
					obj);
		}

	}

	/**
	 * @param n
	 * @param nc
	 * @throws org.omg.CosNaming.NamingContextPackage.NotFound
	 * @throws org.omg.CosNaming.NamingContextPackage.CannotProceed
	 * @throws org.omg.CosNaming.NamingContextPackage.InvalidName
	 * @throws org.omg.CosNaming.NamingContextPackage.AlreadyBound
	 *             roseuid 3E8A61A2000F
	 */
	public void bind_context(NameComponent[] nc, NamingContext obj)
			throws NotFound, CannotProceed, InvalidName, AlreadyBound {
		Name n = new Name(nc);
		Name ctx = n.ctxName();
		NameComponent nb = n.baseNameComponent();

		if (ctx == null) {
			if (names.containsKey(n)) {
				// if the name is still in use, try to ping the object
				org.omg.CORBA.Object s = (org.omg.CORBA.Object) names.get(n);
				if (s._non_existent()) {
					unbind(n.components());
				} else
					throw new AlreadyBound();
			} else if (contexts.containsKey(n)) {
				// if the name is still in use, try to ping the object
				org.omg.CORBA.Object s = (org.omg.CORBA.Object) contexts.get(n);
				if (s._non_existent()) {
					rebind_context(n.components(), obj);
					return;
				}
				throw new AlreadyBound();
			}

			if ((contexts.put(n, obj)) != null)
				throw new CannotProceed(_this(), n.components());
			contexts.put(n, obj);

			System.out.println("Bound context: " + n.toString());
		} else {
			NameComponent[] ncx = new NameComponent[1];
			ncx[0] = nb;
			NamingContextExtHelper.narrow(resolve(ctx.components()))
					.bind_context(ncx, obj);
		}

	}

	/**
	 * @param n
	 * @param obj
	 * @throws org.omg.CosNaming.NamingContextPackage.NotFound
	 * @throws org.omg.CosNaming.NamingContextPackage.CannotProceed
	 * @throws org.omg.CosNaming.NamingContextPackage.InvalidName
	 *             roseuid 3E8A61A2004E
	 */
	public void rebind(NameComponent[] nc, Object obj) throws NotFound,
			CannotProceed, InvalidName {

		if (nc == null || nc.length == 0)
			throw new InvalidName();

		if (obj == null)
			throw new org.omg.CORBA.BAD_PARAM();

		Name n = new Name(nc);
		Name ctx = n.ctxName();
		NameComponent nb = n.baseNameComponent();

		// the name is bound, but it is bound to a context,
		// the client should have been using rebind_context!

		if (contexts.containsKey(n))
			throw new NotFound(NotFoundReason.not_object,
					new NameComponent[] { nb });

		// try remove an existing binding

		org.omg.CORBA.Object _o = (org.omg.CORBA.Object) names.remove(n);
		if (_o != null)
			_o._release();

		if (ctx == null) {
			// do the rebinding in this context

			names.put(n, obj);
			System.out.println("Re-bound name: " + n.toString());
		} else {
			// rebind in the correct context

			NameComponent[] ncx = new NameComponent[1];
			ncx[0] = nb;
			NamingContextExt nce = NamingContextExtHelper.narrow(resolve(ctx
					.components()));
			if (nce == null)
				throw new CannotProceed();
			nce.rebind(ncx, obj);
		}

	}

	/**
	 * @param n
	 * @param nc
	 * @throws org.omg.CosNaming.NamingContextPackage.NotFound
	 * @throws org.omg.CosNaming.NamingContextPackage.CannotProceed
	 * @throws org.omg.CosNaming.NamingContextPackage.InvalidName
	 *             roseuid 3E8A61A2008C
	 */
	public void rebind_context(NameComponent[] nc, NamingContext obj)
			throws NotFound, CannotProceed, InvalidName {
		if (nc == null || nc.length == 0)
			throw new InvalidName();

		if (obj == null)
			throw new org.omg.CORBA.BAD_PARAM();

		Name n = new Name(nc);
		Name ctx = n.ctxName();
		NameComponent nb = n.baseNameComponent();

		// the name is bound, but it is bound to an object,
		// the client should have been using rebind() !

		if (names.containsKey(n))
			throw new NotFound(NotFoundReason.not_context,
					new NameComponent[] { nb });

		// try to remove an existing context binding

		org.omg.CORBA.Object _o = (org.omg.CORBA.Object) contexts.remove(n);
		if (_o != null)
			_o._release();

		if (ctx == null) {
			contexts.put(n, obj);
			System.out.println("Re-Bound context: " + n.baseNameComponent().id);
		}

	}

	/**
	 * @param n
	 * @return org.omg.CORBA.Object
	 * @throws org.omg.CosNaming.NamingContextPackage.NotFound
	 * @throws org.omg.CosNaming.NamingContextPackage.CannotProceed
	 * @throws org.omg.CosNaming.NamingContextPackage.InvalidName
	 *             roseuid 3E8A61A200CB
	 */
	public Object resolve(NameComponent[] nc) throws NotFound, CannotProceed,
			InvalidName {
		if (nc == null || nc.length == 0)
			throw new InvalidName();

		Name n = new Name(nc[0]);
		if (nc.length > 1) {
			NamingContextExt next_context = NamingContextExtHelper
					.narrow((org.omg.CORBA.Object) contexts.get(n));

			if ((next_context == null) || (next_context._non_existent())) {
				throw new NotFound(NotFoundReason.missing_node, nc);
			}

			NameComponent[] nc_prime = new NameComponent[nc.length - 1];

			for (int i = 1; i < nc.length; i++)
				nc_prime[i - 1] = nc[i];

			return next_context.resolve(nc_prime);
		} else {
			org.omg.CORBA.Object result = null;

			result = (org.omg.CORBA.Object) contexts.get(n);

			if (result == null)
				result = (org.omg.CORBA.Object) names.get(n);

			if (result == null || result._non_existent())
				throw new NotFound(NotFoundReason.missing_node, n.components());

			return result;
		}

	}

	/**
	 * @param n
	 * @throws org.omg.CosNaming.NamingContextPackage.NotFound
	 * @throws org.omg.CosNaming.NamingContextPackage.CannotProceed
	 * @throws org.omg.CosNaming.NamingContextPackage.InvalidName
	 *             roseuid 3E8A61A200EA
	 */
	public void unbind(NameComponent[] nc) throws NotFound, CannotProceed,
			InvalidName {

		if (nc == null || nc.length == 0)
			throw new InvalidName();

		Name n = new Name(nc);
		Name ctx = n.ctxName();
		NameComponent nb = n.baseNameComponent();

		if (ctx == null) {
			if (names.containsKey(n)) {
				org.omg.CORBA.Object o = (org.omg.CORBA.Object) names.remove(n);
				o._release();
				System.out.println("Unbound: " + n.toString());
			} else if (contexts.containsKey(n)) {
				org.omg.CORBA.Object o = (org.omg.CORBA.Object) contexts
						.remove(n);
				o._release();
				System.out.println("Unbound: " + n.toString());
			} else {
				System.out.println("Unbind failed for " + n.toString());
				throw new NotFound(NotFoundReason.not_context, n.components());
			}
		} else {
			NameComponent[] ncx = new NameComponent[1];
			ncx[0] = nb;
			NamingContextExtHelper.narrow(resolve(ctx.components()))
					.unbind(ncx);
		}

	}

	private int how_many() {
		return names.size() + contexts.size();
	}

	/**
	 * @param how_many
	 * @param bl
	 * @param bi
	 *            roseuid 3E8A61A20119
	 */
	public void list(int how_many, BindingListHolder bl,
			BindingIteratorHolder bi) {
		Binding[] result;

		int size = how_many();

		Enumeration n = names.keys();
		Enumeration c = contexts.keys();

		if (how_many < size) {
			// counter for copies
			int how_many_ctr = how_many;

			// set up an array with "how_many" bindings

			result = new Binding[how_many];
			for (; n.hasMoreElements() && how_many_ctr > 0; how_many_ctr--) {
				result[how_many_ctr - 1] = new Binding(
						((Name) n.nextElement()).components(),
						BindingType.nobject);
			}

			for (; c.hasMoreElements() && how_many_ctr > 0; how_many_ctr--) {
				result[how_many_ctr - 1] = new Binding(
						((Name) c.nextElement()).components(),
						BindingType.ncontext);
			}

			// create a new BindingIterator for the remaining arrays

			size -= how_many;
			Binding[] rest = new Binding[size];
			for (; n.hasMoreElements() && size > 0; size--) {
				rest[size - 1] = new Binding(
						((Name) n.nextElement()).components(),
						BindingType.nobject);
			}

			for (; c.hasMoreElements() && size > 0; size--) {
				rest[size - 1] = new Binding(
						((Name) c.nextElement()).components(),
						BindingType.ncontext);
			}

			org.omg.CORBA.Object o = null;
			try {
				// Iterators are activated with the RootPOA (transient)
				byte[] oid = rootPoa.activate_object(new BindingIteratorImpl(
						rest));
				o = rootPoa.id_to_reference(oid);
			} catch (Exception ue) {
				ue.printStackTrace();
			}

			bi.value = BindingIteratorHelper.narrow(o);
		} else {
			result = new Binding[size];
			for (; n.hasMoreElements() && size > 0; size--) {
				result[size - 1] = new Binding(
						((Name) n.nextElement()).components(),
						BindingType.nobject);
			}

			for (; c.hasMoreElements() && size > 0; size--) {
				result[size - 1] = new Binding(
						((Name) c.nextElement()).components(),
						BindingType.ncontext);
			}
		}

		bl.value = result;

	}

	/**
	 * @return org.omg.CosNaming.NamingContext roseuid 3E8A61A20167
	 */
	public NamingContext new_context() {
		org.omg.CORBA.Object ctx = null;
		try {
			byte[] oid = (new String(poa.servant_to_id(this)) + "_ctx" + (++child_count))
					.getBytes();

			ctx = poa.create_reference_with_id(oid,
					"IDL:omg.org/CosNaming/NamingContextExt:1.0");
		} catch (Exception ue) {
			ue.printStackTrace();
			System.exit(1);
		}
		return NamingContextExtHelper.narrow(ctx);

	}

	/**
	 * @param n
	 * @return org.omg.CosNaming.NamingContext
	 * @throws org.omg.CosNaming.NamingContextPackage.NotFound
	 * @throws org.omg.CosNaming.NamingContextPackage.AlreadyBound
	 * @throws org.omg.CosNaming.NamingContextPackage.CannotProceed
	 * @throws org.omg.CosNaming.NamingContextPackage.InvalidName
	 *             roseuid 3E8A61A20177
	 */
	public NamingContext bind_new_context(NameComponent[] nc) throws NotFound,
			AlreadyBound, CannotProceed, InvalidName {
		if (nc == null || nc.length == 0)
			throw new InvalidName();

		NamingContextExt ns = NamingContextExtHelper.narrow(new_context());
		bind_context(nc, ns);

		if (ns == null) {
			throw new CannotProceed();
		}
		return ns;

	}

}
